using Digitalmes.Application.Scada.Extensions;
using Digitalmes.Application.Scada.Models;
using Digitalmes.Application.Services;
using Digitalmes.Domain.Entities.Mes.Equipments;

namespace Digitalmes.Application.Scada.Services.Impl;

/// <summary>
/// 设备点检服务。
/// </summary>
internal sealed class EquipmentInspectService(
    IRepository<EquipMachinery> machineryRepo,
    IRepository<EquipInspectionPlan> planRepo,
    IRepository<EquipInspectionRecord> recordRepo,
    IWorkstationQueryService workstationQueryService) : IEquipmentInspectService
{
    public async Task<ScadaResult> InspectAsync(EquipmentInspectInput input, CancellationToken cancellationToken = default)
    {
        // 检索工位信息
        var workstation = await workstationQueryService.GetWorkstationAsync(input.LineCode, input.WsCode);
        if (workstation == null)
        {
            return ScadaResult.Error(ErrorCode.E1702);
        }

        // 找到工位上对应的设备，可能同一工位上有多个设备，按别名来进行定位，未设置别名时查找默认的第一个。
        var machinery = await machineryRepo.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.Alias), m => m.Alias == input.Alias)
            .FirstOrDefaultAsync(m => m.LineId == workstation.LineId && m.WorkstationId == workstation.Id, cancellationToken);
        if (machinery == null)
        {
            return ScadaResult.Error(ErrorCode.E1703);
        }

        // 点检计划，包含自动点检参数（自动）
        var plan = await planRepo.AsQueryable()
            .Includes(m => m.AutoInspectionItems)
            .FirstOrDefaultAsync(m => m.MachineryId == machinery.Id && m.InspectType == InspectTypeEnum.Auto, cancellationToken);
        if (plan == null)
        {
            return ScadaResult.Error(ErrorCode.E1704);
        }

        // 新增设备点检记录
        EquipInspectionRecord inspectionRecord = new()
        {
            PlanId = plan.Id,
            MachineryId = machinery.Id,
            MachineryCode = machinery.MachineryCode,
            MachineryName = machinery.MachineryName,
            InspectType = InspectTypeEnum.Auto,
            LineId = workstation.LineId,
            WorkstationCode = workstation.WsCode,
            StandardPartNo = input.PartNo,
            InspectionTime = DateTime.Now,
            Result = input.PassResult is PassEnum.OK or PassEnum.ForceOK ? QualifiedEnum.Qualified : QualifiedEnum.Unqualified,
            Data = [],
        };

        if (plan.AutoInspectionItems?.Count > 0)
        {
            foreach (var inspectionItem in plan.AutoInspectionItems)
            {
                var data = input.DataList.FirstOrDefault(s => s.TagName == inspectionItem.Symbol);
                if (data != null)
                {
                    EquipInspectionData archive = new()
                    {
                        SubjectName = inspectionItem.SubjectName,
                        Value = NumberUtils.FactorConvertTo(data.GetAsDouble(), inspectionItem.Conversion, inspectionItem.Digits),
                    };

                    // 格式说明：
                    // 上下限优先以设备当前设定的值为准，若设备没设定则按照系统工艺标准配置。
                    // 标记命名格式约定：
                    // 下限值 --> "[主数据信号点]_MixLimit"（标准项中不应该包含单独的"最小"值）;
                    // 上限值 --> "[主数据信号点]_MaxLimit"（同上）;
                    // 结果值 --> "[主数据信号点]_Result"（1-> OK;2->NG，同样标准项中不应该包含单独的"结果"值）。
                    var minLimit = NumberUtils.FactorConvertTo(input.DataList.GetValueAsDouble($"{inspectionItem.Symbol}_MixLimit"), inspectionItem.Conversion, inspectionItem.Digits) ?? inspectionItem.MinLimit;
                    var maxLimit = NumberUtils.FactorConvertTo(input.DataList.GetValueAsDouble($"{inspectionItem.Symbol}_MaxLimit"), inspectionItem.Conversion, inspectionItem.Digits) ?? inspectionItem.MaxLimit;
                    archive.Standard = $"{minLimit}{inspectionItem.MeasurementUnit} ~ {maxLimit}{inspectionItem.MeasurementUnit}";

                    if (inspectionItem.IsCheckThreshold)
                    {
                        // 校验参数标准，上限或下限没有值则对应值不进行比较，只比较存在的那方
                        archive.Result = (!minLimit.HasValue || minLimit <= archive.Value) && (!maxLimit.HasValue || archive.Value <= maxLimit)
                            ? InspectResultEnum.Normal
                            : InspectResultEnum.OOS;
                    }
                    else
                    {
                        // 如果参数有对应的设定结果值，优先按此结果设定
                        var result = input.DataList.GetValueAsInt32($"{inspectionItem.Symbol}_Result");
                        if (result.HasValue)
                        {
                            archive.Result = result switch
                            {
                                1 => InspectResultEnum.Normal,
                                2 => InspectResultEnum.OOS,
                                _ => InspectResultEnum.Normal,
                            };
                        }
                        else
                        {
                            // 根据设备给的结果指定判定（没有结果则为空），一次取值设备结果只有一个，有多个参数时都设定这个结果
                            archive.Result = input.PassResult is PassEnum.OK or PassEnum.ForceOK ? InspectResultEnum.Normal : InspectResultEnum.OOS;
                        }
                    }

                    inspectionRecord.Data.Add(archive);
                }
            }
        }

        // 导航新增
        await recordRepo.Context.InsertNav(inspectionRecord).Include(m => m.Data).ExecuteCommandAsync();

        // 若工步（或工艺步骤）是由上位系统校验参数标准是否合格，则检查是否存在校验结果为 NG 的项并告知下位系统来判定不合格。
        if (plan.IsCheckFinalResult && inspectionRecord.Data.Any(s => s.Result is InspectResultEnum.OOS))
        {
            return ScadaResult.Error(ErrorCode.E1705);
        }

        return ScadaResult.Ok();
    }
}
